﻿#ifndef _REC_READ_BASE_H_
#define _REC_READ_BASE_H_

#include "rec_info.h"
#include <vector>
#include "serial_file_base.h"
#include "FrameFIFOBuf.h"
#include "rec_frmidx.h"

using namespace std;

typedef enum _replay_seek_ret_
{
	SEEK_RET_OK = 0,		//成功

	SEEK_RET_BEGIN,			//之前
	SEEK_RET_END,			//之后

	SEEK_RET_FAILED=-1,		//失败, [文件本身有问题]
}REPLAY_SEEK_RET;

class CRecReadBase
{
public:
	CRecReadBase(int clientID = 0,int channel = -1);
	~CRecReadBase();

    virtual	int Open(const char * fileName, uint32_t fileIndex,int64_t startTime = 0, int64_t endTime = 0,bool bClearBuf = false) = 0;

	int  OpenByFileInfo(REC_FILE_INFO & fileInfo,bool bUseFIFO =true,int64_t startTime = 0, bool bClearBuf = false);

	int  OpenBaseFile(const char * dev,uint32_t fileIndex,STFS_REC_FILEHEAD* pRecordHead,vector<STFS_REC_SEG> & vecSeg);

	int  OpenSerialFile(const char * dev,uint32_t fileIndex);

	int OpenComFile(const char * );

	void Close(bool bImmediate =false);
	void Clear();
	int ReadGPSInfo(uint32_t gpsTm,uchar_t * gpsInfo,int gpsInfoSize);
	int SeekToTime(int64_t time,bool bClear = true);
	int SeekKeyIndex(int64_t time,uint32_t & index);
	int GetIndexByPos(int& curIndex,uint32_t curPos,PLAYBACK_MODE mode);
	int SetPlayMode(PLAYBACK_MODE mode,int speed, bool bReSeek = true);
	int Read_TO_FIFO(int cache_wather = 50);
	int ReadRecordData();
	int ReplayWait(int64_t curTm);
	virtual int ReadFIFONormal()  = 0;
 	virtual int ReadFIFO2Forward()= 0;
	virtual int ReadFIFOForward() = 0;
	virtual int ReadFIFOReback () = 0;

	virtual int ReadFrame(uchar_t * buf, uint32_t bufLen) = 0;

	int GetRecHeader(STFS_REC_FILEHEAD * pRecHeader);
	int GetRecIdxByHeadBuf();
	int ReadRecInfo(STFS_REC_FILEHEAD * pRecHeader = NULL);
	uint32_t GetRecordSize(int64_t startTime, int64_t endTime);
	int GetEndOffset(uint32_t &offset,int64_t endTime);
	int DealBadSector();
	int MkEmptyFrame();
	int MkSwitchFileFrame();
	bool CheckFrame(uchar_t* pBuf, int64_t frTime,int len);
	int  CheckIdxFrame(STFS_REC_IDX * pRecIdx,uchar_t * pBuf, uint32_t bufSize);
	int  CorrectPos(STFS_REC_IDX & recIdx,uchar_t * pBuf,int bufSize);
	int  CheckFrameArea(uint32_t curDataPos);

	int Seek(uint32_t offset);
	int  ReadPos(uint32_t offset, uchar_t * pBuf, uint32_t dataSize);
	int  Read(uchar_t * pBuf, uint32_t dataSize);


	//由于存储在文件当中的音频是针对ASF文件编码的格式，但是在网络传输的需要使用RTP的方式
	static void convert_asf_to_rtp_frame(uint8_t *srcbuf, uint8_t *dstbuf, uint32_t flen);
	static uint8_t convert_asf_to_rtp_byte(uint8_t asfbyte);
	static int PUB_THREAD_CALL ReadFileThd(void * arg);

	CSerialFileBase* GetRecordFile()
	{
		return m_pFile;
	}

	uint64_t GetLoopLBA()
	{
		return m_clientID + m_pFile->get_lba_start() + (int)m_bDownload;
	}

	bool IsOpen()
	{
		if( NULL == m_pFile)
		{
			return false;
		}
		return !m_pFile->is_closed();
	}

	int GetFileIndex()
	{
		return m_fileIdx;
	}

	CReplayFrmBuf* GetFrmBuf()
	{
		return m_pFIFO;
	}

	void SetBufSize(uint32_t bufSize)
	{
		m_nBufSize = bufSize;
	}

	uint32_t GetBufSize()
	{
		return m_nBufSize;
	}

	bool IsWritting()
	{
		return (m_fileStatus != STFS_REC_END_FLAG)? true : false;
	}

	bool IsEffectTime(int64_t curTime)
	{
		if(curTime >= m_startTime && curTime < m_endTime)
		{
			return true;
		}
		return false;
	}

	bool IsDataEnd();
	int GetChannel()
	{
		return m_channel;
	}
	int GetIndexNum()
	{
		return m_maxIndex;
	}
	int GetGpsNum()
	{
		return m_gpsNum;
	}
	int64_t GetStartTime()
	{
		return m_firstTime;
	}

	int64_t GetEndTime()
	{
		if(m_playMode == REPLAY_REBACK)
		{
			return m_startTime - 10;
		}
		else
		{
			return m_endTime + 10;
		}
	}
	int  GetTotalSec()
	{
		return (int)((m_endTime - m_startTime)/1000);
	}
	bool IsReadEnd()
	{
	  	return m_bDataEnd;
	}

	bool IsTelnetDownload()
	{
		return m_bDownload;
	}
	void ClearFIFOBuf()
	{
		if(m_pFIFO)
		{
			m_modeLock.Lock();
			m_pFIFO->reset(m_dataOffset);
			m_modeLock.UnLock();
		}
	}

	void DestroyFIFOBuf()
	{
		if(m_pFIFO)
		{
			m_modeLock.Lock();
#ifndef _WIN32
            m_pFIFO->close();
#endif
			m_modeLock.UnLock();
		}
	}

	uint64_t GetReadID()
	{
		return m_pFile->get_lba_start()+m_clientID;
	}

	STFS_REC_IDX * GetRecIdx()
	{
		return m_pIdxBuf;
	}

	STFS_GPS_IDX * GetGPSInfo()
	{
		return m_pGpsBuf;
	}

	void RegisterClientInfo(int clientID, int ch)
	{
		m_clientID= clientID;
		m_channel = ch;
	}
	void SetDownloadMode(bool bDownload)
	{
		m_bDownload = bDownload;
		m_playMode  = REPLAY_NORMAL;
	}
	void SetBackupMode(bool bBackup)
	{
		m_bLocalBackup = bBackup;
		m_playMode  = REPLAY_NORMAL;
	}
	int  GetDataSize()
	{
		if( NULL == m_pFIFO)
		{
			return 0;
		}
		return m_pFIFO->GetDataSize();
	}
	int GetFileSize()
	{
		return m_fileLen;
	}
	
	int64_t GetLastPalyTime() //获取最后一回放帧的时间
	{
		return m_lastReadTime;
	}
	
	uint32_t GetCurFrmSec() //获取最后一回放帧的时间
	{
		return (uint32_t)((m_frameNO * m_diff_pts)/1000);
	}

	uint32_t GetLastFrmNo() //获取最后一回放帧的时间
	{
		return m_lastfrmNo;
	}
	int GetFrameRate()
	{
		return m_frameRate; //获取视频帧率
	}
	static	bool   MIX_AUDIO;		//是否混合音频数据
protected:
	void StartDataIO();
	void StartReadFile();
	int  InitFIFOBuf(bool bClearBuf = true);
	uchar_t *  GetReplayTmpBuf(uint32_t & bufSize);
protected:

	CSerialFileBase * m_pFile;			//录像读写类
	bool     m_bComFile;				//是否为通用文件
	uint32_t m_version;					//录像文件版本
	uint32_t m_fileLen;					//文件大小

	uint32_t   m_fileIdx;				//文件块编号
	int		 m_segIdx;					//录像段编号
	uint32_t m_channel;					//文件所属通道
	
	int	     m_clientID;				//客户ID
	int64_t  m_firstTime;				//第一帧的时间
	int64_t  m_startTime;				//开始时间
	int64_t  m_endTime;					//结束时间
	int64_t  m_curTime;					//当前读取帧的时间
	int64_t  m_lastTime;				//上一帧视频的时间

	int64_t  m_lastReadTime;	        //最一帧被读取的帧时间
	uint32_t m_frameRate;			 //视频帧率

	bool	 m_bDataEnd;				//是否已经读取完成所有的数据
	uint32_t m_headOffset;			    //通用信息地址
	uint32_t m_recOffset;				//多录像段的信息
	uint32_t m_idxOffset;				//索引的偏移
	uint32_t m_dataOffset;				//数据区的偏移

	uint16_t m_fileStatus;				//文件是否正在写入
	uint16_t m_maxIndex;				//所有索引
	uint16_t m_gpsNum;					//所有GPS信息数量
	uint32_t  m_firtFrmNo;				//首帧的编号
	//索引信息区
	STFS_REC_IDX *m_pIdxBuf;			//指向缓冲区首地址
	STFS_GPS_IDX *m_pGpsBuf;			//gps信息
	uint32_t      m_gpsBufSz;			//gps信息大小
	uint32_t	  m_curPos;				//读取数据的游标，指出当前文件指针的位置
	int			  m_curIndex;			//当前索引序号(SeekToTime时需要重新定位相应视频关键帧前的音频)

	int			  m_stepIFrame;			//I帧跳的间隔
	PLAYBACK_MODE m_playMode;			//回放模式
	int			  m_speed;				//回放速度
	int			  m_noReadCount;		//循环去读的次数
	uint32_t	  m_nBufSize;			//读取缓冲大小
	CCross_Lock   m_modeLock;			//模式锁
	bool          m_bDownload;			//远程下载
	bool          m_bLocalBackup;		//本地备份
	bool          m_bSeek;				//t
	uint64_t      m_fileStartLBA;       //
	uint32_t      m_lastfrmNo;			//上一帧的编号
	//新增加录像段管理
	CReplayFrmBuf       * m_pFIFO;			//缓冲
	CRecFrameIdx    m_frmIdx;			//帧索引
	uchar_t *       m_headBuf;			//头信息缓冲
	CFrmUtility     m_frmTool;			//帧头解析工具
	uint32_t		m_frameNO;		  //生成的帧编号
	uint32_t		m_diff_pts;      //帧间的时间c戳
	cross_thread_t  m_readThdID;
	bool            m_bRawDev;			//是否裸磁盘设备
};
const  uint32_t	 HEAD_BUF_SIZE = SIZE_4KB;		//头信息缓冲
#endif //_REC_READ_BASE_H_
